#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

#include "list/linked_list.h"
#include "gui/gui.h"
#include "utils.h"

typedef struct ListViewData
{
    LinkedList *items;
    void *list;
    int choose_mode;
    int cursor_enabled;
    int focus_pos;
    int divider_size;
    uint32_t divider_color;
    uint32_t cursor_color;
    int current_scroll_coord;
    int target_scroll_coord;
    int scroll_step;
    int (*onGetListLength)(void *list);
    void *(*onGetListHeadEntry)(void *list);
    void *(*onGetListNextEntry)(void *list, void *entry, int id);
    View *(*onNewItemView)(void *list, void *entry, int id);
    int (*onItemClick)(ListView *listView, View *itemView, int id);
    int (*onItemLongClick)(ListView *listView, View *itemView, int id);
} ListViewData;

static int ListViewDestroyData(ListViewData *data)
{
    if (!data)
        return -1;

    LinkedListDestroy(data->items);
    free(data);
    return 0;
}

static void ListViewUpdateScroll(ListViewData *listData)
{
    if (listData->current_scroll_coord != listData->target_scroll_coord)
    {
        int scroll_coord = listData->current_scroll_coord;

        if (scroll_coord < listData->target_scroll_coord)
        {
            scroll_coord += listData->scroll_step;
            if (scroll_coord > listData->target_scroll_coord)
                scroll_coord = listData->target_scroll_coord;
        }
        else if (scroll_coord > listData->target_scroll_coord)
        {
            scroll_coord -= listData->scroll_step;
            if (scroll_coord < listData->target_scroll_coord)
                scroll_coord = listData->target_scroll_coord;
        }

        listData->current_scroll_coord = scroll_coord;
    }
}

static int ListViewMeasureChild(ListView *listView, View *childView, int available_w, int available_h, int *wrap_w, int *wrap_h, int has_divider)
{
    if (!listView || !childView)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    int child_occupy_w = 0;
    int child_occupy_h = 0;

    ViewSetLayoutAvailableSize(childView, available_w, available_h);
    ViewMeasure(childView);
    ViewGetOccupySize(childView, &child_occupy_w, &child_occupy_h);

    if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
    {
        *wrap_w += child_occupy_w;
        if (has_divider)
            *wrap_w += listData->divider_size;
        if (child_occupy_h > *wrap_h)
            *wrap_h = child_occupy_h;
    }
    else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
    {
        *wrap_h += child_occupy_h;
        if (has_divider)
            *wrap_h += listData->divider_size;
        if (child_occupy_w > *wrap_w)
            *wrap_w = child_occupy_w;
    }

    return 0;
}

int ListViewMeasure(ListView *listView)
{
    if (!listView)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    LayoutParams *listParams = &listView->params;

    if (listParams->available_w <= 0 || listParams->available_h <= 0)
    {
        listView->measured_w = 0;
        listView->measured_h = 0;
        return -1;
    }

    int layout_max_w = listParams->available_w - listParams->margin_left - listParams->margin_right;
    int layout_max_h = listParams->available_h - listParams->margin_top - listParams->margin_bottom;
    int layout_wrap_w = 0;
    int layout_wrap_h = 0;

    int children_max_w = layout_max_w - listView->padding_left - listView->padding_right;
    int children_max_h = layout_max_h - listView->padding_top - listView->padding_bottom;
    int children_wrap_w = 0;
    int children_wrap_h = 0;

    if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
        children_max_w = MAX_LAYOUT_WIDTH;
    else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
        children_max_h = MAX_LAYOUT_HEIGHT;

    LinkedListEntry *entry = LinkedListHead(listData->items);
    while (entry)
    {
        LinkedListEntry *next = LinkedListNext(entry);
        View *childView = (View *)LinkedListGetEntryData(entry);
        int has_divider = (next != NULL); // 不绘制最后一个 divider
        ListViewMeasureChild(listView, childView, children_max_w, children_max_h, &children_wrap_w, &children_wrap_h, has_divider);
        entry = next;
    }

    listData->current_scroll_coord = listData->target_scroll_coord = 0;

    layout_wrap_w = children_wrap_w + listView->padding_left + listView->padding_right;
    layout_wrap_h = children_wrap_h + listView->padding_top + listView->padding_bottom;

    listView->wrap_w = layout_wrap_w;
    listView->wrap_h = layout_wrap_h;

    if (listParams->layout_w == TYPE_LAYOUT_SIZE_MATH_PARENT)
        listView->measured_w = layout_max_w;
    else if (listParams->layout_w == TYPE_LAYOUT_SIZE_WRAP_CONTENT)
        listView->measured_w = layout_wrap_w;
    else
        listView->measured_w = listParams->layout_w;
    if (listView->measured_w > layout_max_w)
        listView->measured_w = layout_max_w;
    if (listView->measured_w < 0)
        listView->measured_w = 0;

    if (listParams->layout_h == TYPE_LAYOUT_SIZE_MATH_PARENT)
        listView->measured_h = layout_max_h;
    else if (listParams->layout_h == TYPE_LAYOUT_SIZE_WRAP_CONTENT)
        listView->measured_h = layout_wrap_h;
    else
        listView->measured_h = listParams->layout_h;
    if (listView->measured_h > layout_max_h)
        listView->measured_h = layout_max_h;
    if (listView->measured_h < 0)
        listView->measured_h = 0;

    return 0;
}

static int ListViewDrawChild(ListView *listView, View *childView, int *x, int *y, int min_x, int min_y, int max_x, int max_y, int index, int has_divider)
{
    if (!listView || !childView)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    int child_measured_w = 0;
    int child_measured_h = 0;
    int child_occupy_w = 0;
    int child_occupy_h = 0;
    int next_x = *x;
    int next_y = *y;

    ViewGetOccupySize(childView, &child_occupy_w, &child_occupy_h);

    int dx = *x + child_occupy_w;
    int dy = *y + child_occupy_h;

    if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
    {
        next_x = dx;
        if (has_divider)
            next_x += listData->divider_size;
        if (dx <= min_x)
            goto NEXT;
        if (*x >= max_x)
            return -1;
    }
    else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
    {
        next_y = dy;
        if (has_divider)
            next_y += listData->divider_size;
        if (dy <= min_y)
            goto NEXT;
        if (*y >= max_y)
            return -1;
    }

    if (listData->cursor_enabled && index == listData->focus_pos)
    {
        ViewSetFocus(childView, 1);
        ViewSetBgColor(childView, listData->cursor_color);
    }
    else
    {
        ViewSetFocus(childView, 0);
        ViewSetBgColor(childView, 0);
    }
    ViewSetLayoutPosition(childView, *x, *y);
    ViewDraw(childView);

    // 绘制分割线
    if (has_divider && listData->divider_color && listData->divider_size > 0)
    {
        ViewGetMeasuredSize(childView, &child_measured_w, &child_measured_h);

        if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
            GUI_DrawFillRectangle(dx, *y, listData->divider_size, child_measured_h, listData->divider_color);
        else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
            GUI_DrawFillRectangle(*x, dy, child_measured_w, listData->divider_size, listData->divider_color);
    }

NEXT:
    *x = next_x;
    *y = next_y;

    return 0;
}

int ListViewDraw(ListView *listView)
{
    if (!listView)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    LayoutParams *listParams = &listView->params;

    if (listView->measured_w <= 0 || listView->measured_h <= 0)
        return 0;

    ListViewUpdateScroll(listData); // 更新滚动数据

    int layout_x = listParams->layout_x + listParams->margin_left;
    int layout_y = listParams->layout_y + listParams->margin_top;
    int layout_w = listView->measured_w;
    int layout_h = listView->measured_h;

    int children_sx = layout_x + listView->padding_left;
    int children_sy = layout_y + listView->padding_top;
    int children_dx = layout_x + layout_w - listView->padding_right;
    int children_dy = layout_y + layout_h - listView->padding_bottom;
    int children_w = children_dx - children_sx;
    int children_h = children_dy - children_sy;

    if (listView->bg_color)
        GUI_DrawFillRectangle(layout_x, layout_y, layout_w, layout_h, listView->bg_color);

    GUI_SetClipping(layout_x, layout_y, layout_w, layout_h);

    int child_x = children_sx;
    int child_y = children_sy;

    if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
        child_x += listData->current_scroll_coord;
    else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
        child_y += listData->current_scroll_coord;

    if (listData->items)
    {
        GUI_SetClipping(children_sx, children_sy, children_w, children_h);

        int index = 0;
        LinkedListEntry *entry = LinkedListHead(listData->items);
        while (entry)
        {
            LinkedListEntry *next = LinkedListNext(entry);
            View *childView = (View *)LinkedListGetEntryData(entry);
            int has_divider = (next != NULL); // 不绘制最后一个 divider
            if (ListViewDrawChild(listView, childView, &child_x, &child_y, children_sx, children_sy, children_dx, children_dy, index, has_divider) < 0)
                break;
            entry = next;
            index++;
        }

        GUI_UnsetClipping();

        // Draw scrollbar
        if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL) // 暂时只支持绘制垂直滚动条
        {
            int scrollbar_track_x = layout_x + layout_w - GUI_DEF_SCROLLBAR_SIZE;
            int scrollbar_track_y = layout_y;
            int scrollbar_track_height = layout_h;
            int its_measured_h = 0;
            int its_wrap_h = 0;
            ViewGetMeasuredContentSize(listView, NULL, &its_measured_h);
            ViewGetWrapContentSize(listView, NULL, &its_wrap_h);
            GUI_DrawVerticalScrollbar(scrollbar_track_x, scrollbar_track_y, scrollbar_track_height,
                                      its_wrap_h, its_measured_h, 0 - listData->current_scroll_coord, 0);
        }
    }

    GUI_UnsetClipping();

    return 0;
}

View *ListViewFindItemViewByNum(ListView *listView, int n)
{
    if (!listView || !listView->viewdata)
        return NULL;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    LinkedListEntry *entry = LinkedListFindByNum(listData->items, n);

    return (ItemView *)LinkedListGetEntryData(entry);
}

int ListViewRemoveItemView(ListView *listView, View *itemView)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    LinkedListEntry *entry = LinkedListFindByData(listData->items, itemView);

    return LinkedListRemove(listData->items, entry);
}

int ListViewRemoveItemViewByNum(ListView *listView, int n)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    LinkedListEntry *entry = LinkedListFindByNum(listData->items, n);

    return LinkedListRemove(listData->items, entry);
}

int ListViewAddItemView(ListView *listView, View *itemView)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    if (LinkedListAdd(listData->items, itemView))
        return 1;

    return 0;
}

int ListViewEmptyItemViews(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    LinkedListEmpty(listData->items);

    return 0;
}

int ListViewSetOnItemClickCallback(ListView *listView, int (*onItemClick)(ListView *listView, View *itemView, int id))
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    listData->onItemClick = onItemClick;

    return 0;
}

int ListViewSetOnItemLongClickCallback(ListView *listView, int (*onItemLongClick)(ListView *listView, View *itemView, int id))
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    listData->onItemLongClick = onItemLongClick;

    return 0;
}

int ListViewGetSrcollCoordByPos(ListView *listView, int pos)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    int coord = 0;

    LinkedListEntry *entry = LinkedListHead(listData->items);
    int i;
    for (i = 0; i < pos && entry; i++)
    {
        View *itemView = (View *)LinkedListGetEntryData(entry);
        int occupy_size = 0;

        if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
            ViewGetOccupySize(itemView, &occupy_size, NULL);
        else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
            ViewGetOccupySize(itemView, NULL, &occupy_size);

        occupy_size += listData->divider_size;
        coord -= occupy_size;
        entry = LinkedListNext(entry);
    }

    return coord;
}

int ListViewGetPosBySrcollCoord(ListView *listView, int scroll_coord)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;

    int pos = 0;
    int coord = 0;
    int wrap_content_size = 0;

    if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
        ViewGetWrapContentSize(listView, &wrap_content_size, NULL);
    else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
        ViewGetWrapContentSize(listView, NULL, &wrap_content_size);

    int max_scroll_coord = 0;
    int min_scroll_coord = 0 - wrap_content_size;

    if (scroll_coord < min_scroll_coord)
        scroll_coord = min_scroll_coord;
    if (scroll_coord > max_scroll_coord)
        scroll_coord = max_scroll_coord;

    LinkedListEntry *entry = LinkedListHead(listData->items);
    while (entry)
    {
        View *itemView = (View *)LinkedListGetEntryData(entry);
        int occupy_size = 0;

        if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
            ViewGetOccupySize(itemView, &occupy_size, NULL);
        else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
            ViewGetOccupySize(itemView, NULL, &occupy_size);

        if (coord <= scroll_coord && coord + occupy_size > scroll_coord)
            return pos;

        coord -= occupy_size;
        pos++;
        entry = LinkedListNext(entry);
    }

    return pos;
}

int ListViewSetCurrentScrollCoord(ListView *listView, int coord)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    listData->current_scroll_coord = coord;
    return 0;
}

int ListViewGetCurrentScrollCoord(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    return listData->current_scroll_coord;
}

int ListViewSetTargetScrollCoord(ListView *listView, int coord, int smooth)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    int measured_content_size = 0;
    int wrap_content_size = 0;

    if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
    {
        ViewGetMeasuredContentSize(listView, &measured_content_size, NULL);
        ViewGetWrapContentSize(listView, &wrap_content_size, NULL);
    }
    else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
    {
        ViewGetMeasuredContentSize(listView, NULL, &measured_content_size);
        ViewGetWrapContentSize(listView, NULL, &wrap_content_size);
    }

    int max_scroll_coord = 0;
    int min_scroll_coord = MIN(measured_content_size - wrap_content_size, 0);

    if (coord < min_scroll_coord)
        coord = min_scroll_coord;
    if (coord > max_scroll_coord)
        coord = max_scroll_coord;

    if (listData->target_scroll_coord != coord)
    {
        listData->target_scroll_coord = coord;

        if (smooth) // 平滑滚动
        {
            listData->scroll_step = (listData->target_scroll_coord - listData->current_scroll_coord) / 10;
            if (listData->scroll_step < 0)
                listData->scroll_step = 0 - listData->scroll_step;
            if (listData->scroll_step < 1)
                listData->scroll_step = 1;
        }
        else // 直接跳转
        {
            listData->current_scroll_coord = listData->target_scroll_coord;
        }
    }

    return 0;
}

int ListViewGetTargetScrollCoord(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    return listData->target_scroll_coord;
}

int ListViewSetTopPos(ListView *listView, int pos, int smooth)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    int length = LinkedListGetLength(listData->items);
    int coord = 0;

    if (pos > length - 1)
        pos = length - 1;
    if (pos < 0)
        pos = 0;

    if (pos > 0)
        coord = ListViewGetSrcollCoordByPos(listView, pos);

    ListViewSetTargetScrollCoord(listView, coord, smooth);

    return 0;
}

int ListViewGetTopPos(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    return ListViewGetPosBySrcollCoord(listView, listData->target_scroll_coord);
}

int ListViewSetFocusPos(ListView *listView, int pos, int smooth)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    int length = LinkedListGetLength(listData->items);
    int coord = 0;

    if (pos > length - 1)
        pos = length - 1;
    if (pos < 0)
        pos = 0;

    if (pos > 0)
    {
        coord = ListViewGetSrcollCoordByPos(listView, pos);

        View *itemView = ListViewFindItemViewByNum(listView, pos);
        if (itemView)
        {
            int measured_content_size = 0;
            int occupy_size = 0;

            if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
            {
                ViewGetMeasuredContentSize(listView, &measured_content_size, NULL);
                ViewGetOccupySize(itemView, &occupy_size, NULL);
            }
            else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
            {
                ViewGetMeasuredContentSize(listView, NULL, &measured_content_size);
                ViewGetOccupySize(itemView, NULL, &occupy_size);
            }

            coord += (measured_content_size - occupy_size) / 2; // 设置focus居中
        }
    }

    ListViewSetTargetScrollCoord(listView, coord, smooth);
    listData->focus_pos = pos;

    return 0;
}

int ListViewGetFocusPos(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    return listData->focus_pos;
}

int ListViewSetDividerSize(ListView *listView, int size)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    listData->divider_size = size;

    return 0;
}

int ListViewGetDividerSize(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    return listData->divider_size;
}

int ListViewSetDividerColor(ListView *listView, uint32_t color)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    listData->divider_color = color;

    return 0;
}

uint32_t ListViewGetDividerColor(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    return listData->divider_color;
}

int ListViewSetCursorEnabled(ListView *listView, int enabled)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    listData->cursor_enabled = enabled;

    return 0;
}

int ListViewIsCursorEnabled(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    return listData->cursor_enabled;
}

int ListViewSetCursorColor(ListView *listView, uint32_t color)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    listData->cursor_color = color;

    return 0;
}

uint32_t ListViewGetCursorColor(ListView *listView)
{
    if (!listView || !listView->viewdata)
        return 0;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    return listData->cursor_color;
}

int ListViewMoveTopPos(ListView *listView, int move_type, int smooth)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    int coord = listData->target_scroll_coord;
    int measured_content_size = 0;

    if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
        ViewGetMeasuredContentSize(listView, &measured_content_size, NULL);
    else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
        ViewGetMeasuredContentSize(listView, NULL, &measured_content_size);

    if (move_type == TYPE_MOVE_UP)
    {
        int top_pos = ListViewGetPosBySrcollCoord(listView, listData->target_scroll_coord);
        coord = ListViewGetSrcollCoordByPos(listView, top_pos - 1);
    }
    else if (move_type == TYPE_MOVE_DOWN)
    {
        int top_pos = ListViewGetPosBySrcollCoord(listView, listData->target_scroll_coord);
        coord = ListViewGetSrcollCoordByPos(listView, top_pos + 1);
    }
    else if (move_type == TYPE_MOVE_LEFT)
    {
        coord = listData->target_scroll_coord + measured_content_size;
    }
    else if (move_type == TYPE_MOVE_RIGHT)
    {
        coord = listData->target_scroll_coord - measured_content_size;
    }

    ListViewSetTargetScrollCoord(listView, coord, smooth);

    return 0;
}

int ListViewMoveFocusPos(ListView *listView, int move_type, int smooth)
{
    if (!listView || !listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    int focus_pos = listData->focus_pos;
    int measured_content_size = 0;

    if (listView->orientation == TYPE_LAYOUT_ORIENTATION_HORIZONTAL)
        ViewGetMeasuredContentSize(listView, &measured_content_size, NULL);
    else if (listView->orientation == TYPE_LAYOUT_ORIENTATION_VERTICAL)
        ViewGetMeasuredContentSize(listView, NULL, &measured_content_size);

    if (move_type == TYPE_MOVE_UP)
    {
        if (focus_pos > 0)
            focus_pos--;
    }
    else if (move_type == TYPE_MOVE_DOWN)
    {
        if (focus_pos < LinkedListGetLength(listData->items) - 1)
            focus_pos++;
    }
    else if (move_type == TYPE_MOVE_LEFT)
    {
        int coord = ListViewGetSrcollCoordByPos(listView, focus_pos) + measured_content_size;
        focus_pos = ListViewGetPosBySrcollCoord(listView, coord);
    }
    else if (move_type == TYPE_MOVE_RIGHT)
    {
        int coord = ListViewGetSrcollCoordByPos(listView, focus_pos) - measured_content_size;
        focus_pos = ListViewGetPosBySrcollCoord(listView, coord);
    }

    if (focus_pos != listData->focus_pos)
        ListViewSetFocusPos(listView, focus_pos, smooth);

    return 0;
}

int ListViewInit(ListView *listView)
{
    if (!listView)
        return -1;

    memset(listView, 0, sizeof(ListView));

    listView->viewdata = calloc(1, sizeof(ListViewData));
    if (!listView->viewdata)
        return -1;

    ListViewData *listData = (ListViewData *)listView->viewdata;
    listData->items = NewLinkedList();
    if (!listData->items)
        goto FAILED;
    LinkedListSetFreeEntryDataCallback(listData->items, (void *)ViewFinish);

    listView->onMeasure = ListViewMeasure;
    listView->onDraw = ListViewDraw;
    listView->onFinish = ListViewDestroy;

    return 0;

FAILED:
    ListViewDeinit(listView);
    return -1;
}

int ListViewDeinit(ListView *listView)
{
    if (!listView)
        return -1;

    ListViewDestroyData((ListViewData *)listView->viewdata);
    memset(listView, 0, sizeof(ListView));

    return 0;
}

ListView *NewListView()
{
    ListView *listView = (ListView *)malloc(sizeof(ListView));
    if (!listView)
        return NULL;

    if (ListViewInit(listView) < 0)
    {
        free(listView);
        return NULL;
    }

    return listView;
}

int ListViewDestroy(ListView *listView)
{
    if (!listView)
        return -1;

    if (listView->dont_free)
        return 0;

    ListViewDestroyData((ListViewData *)listView->viewdata);
    free(listView);

    return 0;
}
